"""
Teams API Routes
Team management, member management, and file assignment operations
Updated with bcrypt support
"""

from datetime import datetime
from typing import List, Optional
from fastapi import APIRouter, Depends, HTTPException, status, Query
from pydantic import BaseModel, Field
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func, and_, or_
import uuid
import bcrypt

from app.core.database import get_business_db
from app.core.security import get_current_user
from app.models.business import Team, TeamMember, TeamFileAssignment, User, ActivityLog

router = APIRouter()


# Pydantic models for request/response
class TeamCreate(BaseModel):
    """Team creation request model"""
    name: str = Field(..., min_length=1, max_length=255)
    description: Optional[str] = None


class TeamUpdate(BaseModel):
    """Team update request model"""
    name: Optional[str] = Field(None, min_length=1, max_length=255)
    description: Optional[str] = None


class TeamResponse(BaseModel):
    """Team response model"""
    id: str
    name: str
    description: Optional[str]
    created_by: str
    created_at: datetime
    updated_at: datetime
    member_count: Optional[int] = 0
    assignment_count: Optional[int] = 0

    class Config:
        from_attributes = True


class TeamMemberCreate(BaseModel):
    """Team member creation request model"""
    user_id: str
    role: str = Field(default="MEMBER", pattern="^(ADMIN|MEMBER)$")


class TeamFileAssignmentCreate(BaseModel):
    """Team file assignment creation model"""
    file_pattern: str = Field(..., min_length=1)
    description: Optional[str] = None
    is_active: bool = True


class TeamFileAssignmentResponse(BaseModel):
    """Team file assignment response model"""
    id: str
    team_id: str
    file_pattern: str
    description: Optional[str]
    is_active: bool
    created_by: str
    created_at: datetime
    updated_at: datetime

    class Config:
        from_attributes = True


class ApiResponse(BaseModel):
    """Generic API response model"""
    success: bool
    data: Optional[dict] = None
    message: Optional[str] = None


@router.get("/", response_model=List[TeamResponse])
async def get_teams(
    skip: int = Query(0, ge=0),
    limit: int = Query(100, ge=1, le=1000),
    current_user: dict = Depends(get_current_user),
    db: AsyncSession = Depends(get_business_db)
):
    """Get all teams with member and assignment counts"""
    try:
        # Query teams with member and assignment counts
        query = select(
            Team,
            func.count(TeamMember.id).label('member_count'),
            func.count(TeamFileAssignment.id).label('assignment_count')
        ).outerjoin(
            TeamMember, Team.id == TeamMember.team_id
        ).outerjoin(
            TeamFileAssignment, Team.id == TeamFileAssignment.team_id
        ).group_by(Team.id).offset(skip).limit(limit)

        result = await db.execute(query)
        rows = result.fetchall()

        teams = []
        for row in rows:
            team, member_count, assignment_count = row
            team_dict = {
                **team.__dict__,
                "member_count": member_count or 0,
                "assignment_count": assignment_count or 0
            }
            teams.append(TeamResponse(**team_dict))

        return teams

    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to retrieve teams: {str(e)}"
        )


@router.get("/{team_id}", response_model=TeamResponse)
async def get_team(
    team_id: str,
    current_user: dict = Depends(get_current_user),
    db: AsyncSession = Depends(get_business_db)
):
    """Get specific team details"""
    try:
        # Query team with counts
        query = select(
            Team,
            func.count(TeamMember.id).label('member_count'),
            func.count(TeamFileAssignment.id).label('assignment_count')
        ).outerjoin(
            TeamMember, Team.id == TeamMember.team_id
        ).outerjoin(
            TeamFileAssignment, Team.id == TeamFileAssignment.team_id
        ).where(Team.id == team_id).group_by(Team.id)

        result = await db.execute(query)
        row = result.first()

        if not row:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Team not found"
            )

        team, member_count, assignment_count = row
        team_dict = {
            **team.__dict__,
            "member_count": member_count or 0,
            "assignment_count": assignment_count or 0
        }

        return TeamResponse(**team_dict)

    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to retrieve team: {str(e)}"
        )


@router.post("/", response_model=TeamResponse)
async def create_team(
    team_data: TeamCreate,
    current_user: dict = Depends(get_current_user),
    db: AsyncSession = Depends(get_business_db)
):
    """Create a new team"""
    try:
        team_id = str(uuid.uuid4())

        # Create team
        team = Team(
            id=team_id,
            name=team_data.name,
            description=team_data.description,
            created_by=current_user["user_id"]
        )

        db.add(team)

        # Add creator as admin member
        member = TeamMember(
            id=str(uuid.uuid4()),
            team_id=team_id,
            user_id=current_user["user_id"],
            role="ADMIN",
            status="ACTIVE",
            joined_at=datetime.utcnow()
        )
        db.add(member)

        # Log activity
        activity = ActivityLog(
            id=str(uuid.uuid4()),
            user_id=current_user["user_id"],
            team_id=team_id,
            action="CREATE",
            resource_type="TEAM",
            resource_id=team_id,
            details=f"Created team: {team_data.name}"
        )
        db.add(activity)

        await db.commit()
        await db.refresh(team)

        # Add member count to response
        team_dict = team.__dict__
        team_dict["member_count"] = 1
        team_dict["assignment_count"] = 0

        return TeamResponse(**team_dict)

    except Exception as e:
        await db.rollback()
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to create team: {str(e)}"
        )


@router.put("/{team_id}", response_model=TeamResponse)
async def update_team(
    team_id: str,
    team_data: TeamUpdate,
    current_user: dict = Depends(get_current_user),
    db: AsyncSession = Depends(get_business_db)
):
    """Update team details"""
    try:
        # Get team
        query = select(Team).where(Team.id == team_id)
        result = await db.execute(query)
        team = result.scalar_one_or_none()

        if not team:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Team not found"
            )

        # Update team
        if team_data.name:
            team.name = team_data.name
        if team_data.description is not None:
            team.description = team_data.description

        team.updated_at = datetime.utcnow()

        # Log activity
        activity = ActivityLog(
            id=str(uuid.uuid4()),
            user_id=current_user["user_id"],
            team_id=team_id,
            action="UPDATE",
            resource_type="TEAM",
            resource_id=team_id,
            details=f"Updated team: {team.name}"
        )
        db.add(activity)

        await db.commit()
        await db.refresh(team)

        # Add counts to response
        member_count = await db.scalar(
            select(func.count(TeamMember.id)).where(TeamMember.team_id == team_id)
        )
        assignment_count = await db.scalar(
            select(func.count(TeamFileAssignment.id)).where(TeamFileAssignment.team_id == team_id)
        )

        team_dict = team.__dict__
        team_dict["member_count"] = member_count or 0
        team_dict["assignment_count"] = assignment_count or 0

        return TeamResponse(**team_dict)

    except HTTPException:
        raise
    except Exception as e:
        await db.rollback()
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to update team: {str(e)}"
        )


@router.delete("/{team_id}", response_model=ApiResponse)
async def delete_team(
    team_id: str,
    current_user: dict = Depends(get_current_user),
    db: AsyncSession = Depends(get_business_db)
):
    """Delete a team"""
    try:
        # Get team
        query = select(Team).where(Team.id == team_id)
        result = await db.execute(query)
        team = result.scalar_one_or_none()

        if not team:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Team not found"
            )

        # Delete related records in proper order to handle foreign key constraints

        # 1. Delete team file assignments
        from app.models.business import TeamFileAssignment
        assignment_query = select(TeamFileAssignment).where(TeamFileAssignment.team_id == team_id)
        assignment_result = await db.execute(assignment_query)
        assignments = assignment_result.scalars().all()
        for assignment in assignments:
            await db.delete(assignment)

        # 2. Delete team members
        member_query = select(TeamMember).where(TeamMember.team_id == team_id)
        member_result = await db.execute(member_query)
        members = member_result.scalars().all()
        for member in members:
            await db.delete(member)

        # 3. Delete related activity logs (optional, but keeps things clean)
        from app.models.business import ActivityLog
        activity_query = select(ActivityLog).where(
            (ActivityLog.team_id == team_id) &
            (ActivityLog.resource_type == "TEAM") &
            (ActivityLog.resource_id == team_id)
        )
        activity_result = await db.execute(activity_query)
        activities = activity_result.scalars().all()
        for activity in activities:
            await db.delete(activity)

        # 4. Finally delete the team
        await db.delete(team)

        # Log activity (this one stays as it's for audit trail)
        log_activity = ActivityLog(
            id=str(uuid.uuid4()),
            user_id=current_user["user_id"],
            team_id=None,  # Team is deleted, so no team_id
            action="DELETE",
            resource_type="TEAM",
            resource_id=team_id,
            details=f"Deleted team: {team.name}"
        )
        db.add(log_activity)

        await db.commit()

        return ApiResponse(
            success=True,
            message="Team deleted successfully"
        )

    except HTTPException:
        raise
    except Exception as e:
        await db.rollback()
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to delete team: {str(e)}"
        )


# Response models for team members
class TeamMemberResponse(BaseModel):
    """Team member response model"""
    id: str
    team_id: str
    user_id: str
    role: str
    status: str
    joined_at: datetime
    user: dict

    class Config:
        from_attributes = True


class TeamMemberCreate(BaseModel):
    """Team member creation request model"""
    user_name: str = Field(..., min_length=1)
    role: str = Field(..., pattern="^(PL|SE|MDE)$")


class TeamMemberUpdate(BaseModel):
    """Team member update request model"""
    role: str = Field(..., pattern="^(PL|SE|MDE)$")


@router.get("/{team_id}/members", response_model=List[TeamMemberResponse])
async def get_team_members(
    team_id: str,
    current_user: dict = Depends(get_current_user),
    db: AsyncSession = Depends(get_business_db)
):
    """Get all members of a team"""
    try:
        # Verify team exists
        team_query = select(Team).where(Team.id == team_id)
        team_result = await db.execute(team_query)
        team = team_result.scalar_one_or_none()

        if not team:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Team not found"
            )

        # Get team members with user info
        query = select(TeamMember, User).join(
            User, TeamMember.user_id == User.id
        ).where(TeamMember.team_id == team_id).order_by(TeamMember.joined_at.desc())

        result = await db.execute(query)
        rows = result.fetchall()

        members = []
        for team_member, user in rows:
            member_dict = {
                **team_member.__dict__,
                "user": {
                    "id": user.id,
                    "name": user.name,
                    "email": user.email,
                    "avatar_url": None
                }
            }
            members.append(TeamMemberResponse(**member_dict))

        return members

    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to retrieve team members: {str(e)}"
        )


@router.post("/{team_id}/members", response_model=TeamMemberResponse)
async def add_team_member(
    team_id: str,
    member_data: TeamMemberCreate,
    current_user: dict = Depends(get_current_user),
    db: AsyncSession = Depends(get_business_db)
):
    """Add a member to a team"""
    try:
        # Verify team exists
        team_query = select(Team).where(Team.id == team_id)
        team_result = await db.execute(team_query)
        team = team_result.scalar_one_or_none()

        if not team:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Team not found"
            )

        # Verify user exists by name
        user_query = select(User).where(User.name == member_data.user_name)
        user_result = await db.execute(user_query)
        user = user_result.scalar_one_or_none()

        if not user:
            # If user doesn't exist, create a new user
            password_hash = bcrypt.hashpw("default_password".encode('utf-8'), bcrypt.gensalt())
            user = User(
                id=str(uuid.uuid4()),
                name=member_data.user_name,
                email=f"{member_data.user_name.lower().replace(' ', '')}@example.com",  # Generate a placeholder email
                password_hash=password_hash,
                role="MEMBER"
            )
            db.add(user)
            await db.flush()  # Get the user ID

        # Check if user is already a member
        existing_query = select(TeamMember).where(
            and_(TeamMember.team_id == team_id, TeamMember.user_id == user.id)
        )
        existing_result = await db.execute(existing_query)
        existing_member = existing_result.scalar_one_or_none()

        if existing_member:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="User is already a member of this team"
            )

        # Add member
        member = TeamMember(
            id=str(uuid.uuid4()),
            team_id=team_id,
            user_id=user.id,
            role=member_data.role,
            status="ACTIVE",
            joined_at=datetime.utcnow()
        )
        db.add(member)

        # Log activity
        activity = ActivityLog(
            id=str(uuid.uuid4()),
            user_id=current_user["user_id"],
            team_id=team_id,
            action="CREATE",
            resource_type="TEAM_MEMBER",
            resource_id=member.id,
            details=f"Added member {user.name} ({user.email}) as {member_data.role}"
        )
        db.add(activity)

        await db.commit()
        await db.refresh(member)

        # Get user info for response
        user_info = {
            "id": user.id,
            "name": user.name,
            "email": user.email,
            "avatar_url": None
        }

        member_dict = {
            **member.__dict__,
            "user": user_info
        }
        return TeamMemberResponse(**member_dict)

    except HTTPException:
        raise
    except Exception as e:
        await db.rollback()
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to add team member: {str(e)}"
        )


@router.put("/{team_id}/members/{user_id}", response_model=TeamMemberResponse)
async def update_team_member_role(
    team_id: str,
    user_id: str,
    member_data: TeamMemberUpdate,
    current_user: dict = Depends(get_current_user),
    db: AsyncSession = Depends(get_business_db)
):
    """Update a team member's role"""
    try:
        # Get member
        query = select(TeamMember).where(
            and_(TeamMember.team_id == team_id, TeamMember.user_id == user_id)
        )
        result = await db.execute(query)
        member = result.scalar_one_or_none()

        if not member:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Team member not found"
            )

        # Prevent modifying OWNER role
        if member.role == "OWNER":
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Cannot modify OWNER role"
            )

        # Update role
        member.role = member_data.role

        # Log activity
        activity = ActivityLog(
            id=str(uuid.uuid4()),
            user_id=current_user["user_id"],
            team_id=team_id,
            action="UPDATE",
            resource_type="TEAM_MEMBER",
            resource_id=member.id,
            details=f"Updated member role to {member_data.role}"
        )
        db.add(activity)

        await db.commit()
        await db.refresh(member)

        # Get user info for response
        user_query = select(User).where(User.id == user_id)
        user_result = await db.execute(user_query)
        user = user_result.scalar_one_or_none()

        user_info = {
            "id": user.id,
            "name": user.name,
            "email": user.email,
            "avatar_url": None
        }

        member_dict = {
            **member.__dict__,
            "user": user_info
        }
        return TeamMemberResponse(**member_dict)

    except HTTPException:
        raise
    except Exception as e:
        await db.rollback()
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to update team member role: {str(e)}"
        )


@router.delete("/{team_id}/members/{user_id}", response_model=ApiResponse)
async def remove_team_member(
    team_id: str,
    user_id: str,
    current_user: dict = Depends(get_current_user),
    db: AsyncSession = Depends(get_business_db)
):
    """Remove a member from a team"""
    try:
        # Get member
        query = select(TeamMember).where(
            and_(TeamMember.team_id == team_id, TeamMember.user_id == user_id)
        )
        result = await db.execute(query)
        member = result.scalar_one_or_none()

        if not member:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Team member not found"
            )

        # Prevent removing OWNER
        if member.role == "OWNER":
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Cannot remove OWNER from team"
            )

        # Get user info for logging
        user_query = select(User).where(User.id == user_id)
        user_result = await db.execute(user_query)
        user = user_result.scalar_one_or_none()

        # Delete member
        await db.delete(member)

        # Log activity
        activity = ActivityLog(
            id=str(uuid.uuid4()),
            user_id=current_user["user_id"],
            team_id=team_id,
            action="DELETE",
            resource_type="TEAM_MEMBER",
            resource_id=member.id,
            details=f"Removed member {user.name} ({user.email})"
        )
        db.add(activity)

        await db.commit()

        return ApiResponse(
            success=True,
            message="Team member removed successfully"
        )

    except HTTPException:
        raise
    except Exception as e:
        await db.rollback()
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to remove team member: {str(e)}"
        )


@router.get("/{team_id}/assignments", response_model=List[TeamFileAssignmentResponse])
async def get_team_file_assignments(
    team_id: str,
    current_user: dict = Depends(get_current_user),
    db: AsyncSession = Depends(get_business_db)
):
    """Get file assignments for a team"""
    try:
        query = select(TeamFileAssignment).where(
            and_(TeamFileAssignment.team_id == team_id, TeamFileAssignment.is_active == True)
        )
        result = await db.execute(query)
        assignments = result.scalars().all()

        return [TeamFileAssignmentResponse.from_orm(assignment) for assignment in assignments]

    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to retrieve assignments: {str(e)}"
        )


@router.post("/{team_id}/assignments", response_model=TeamFileAssignmentResponse)
async def create_team_file_assignment(
    team_id: str,
    assignment_data: TeamFileAssignmentCreate,
    current_user: dict = Depends(get_current_user),
    db: AsyncSession = Depends(get_business_db)
):
    """Create a file assignment for a team"""
    try:
        # Verify team exists
        team_query = select(Team).where(Team.id == team_id)
        team_result = await db.execute(team_query)
        team = team_result.scalar_one_or_none()

        if not team:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Team not found"
            )

        # Create assignment
        assignment = TeamFileAssignment(
            id=str(uuid.uuid4()),
            team_id=team_id,
            file_pattern=assignment_data.file_pattern,
            description=assignment_data.description,
            is_active=assignment_data.is_active,
            created_by=current_user["user_id"]
        )

        db.add(assignment)

        # Log activity
        activity = ActivityLog(
            id=str(uuid.uuid4()),
            user_id=current_user["user_id"],
            team_id=team_id,
            action="CREATE",
            resource_type="ASSIGNMENT",
            resource_id=assignment.id,
            details=f"Created file assignment: {assignment_data.file_pattern}"
        )
        db.add(activity)

        await db.commit()
        await db.refresh(assignment)

        return TeamFileAssignmentResponse.from_orm(assignment)

    except HTTPException:
        raise
    except Exception as e:
        await db.rollback()
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to create assignment: {str(e)}"
        )